/*
 * ShotHttpSender.cpp
 *
 *  Created on: Oct 7, 2012
 *      Author: Administrator
 */

#include "ShotHttpSender.h"
#include "Util.h"

using namespace Osp::Base;
using namespace Osp::Base::Utility;
using namespace Osp::Base::Runtime;
using namespace Osp::Base::Collection;
using namespace Osp::Net::Http;
using namespace Osp::Net::Sockets;
using namespace Osp::Net;

ShotHttpSender::ShotHttpSender() {

}

ShotHttpSender::ShotHttpSender(Shooter* pShooter, String* pHostAddr) {
	shooter = pShooter;
	String* pProxyAddr = null;
	hostAddr = pHostAddr;
	session = new HttpSession();
	session->Construct(NET_HTTP_SESSION_MODE_NORMAL, pProxyAddr, *hostAddr, null);

	store = Util::GetShotStore();
	store -> Clean();

	Construct();
	Start();
	SendUserEvent(1, null);
}

ShotHttpSender::~ShotHttpSender() {
	AppLog("Destroying ShotHttpSender");
}

void
ShotHttpSender::OnTransactionAborted (HttpSession &httpSession, HttpTransaction &httpTransaction, result r) {
	AppLogDebug("OnTransactionAborted with result: %S", GetErrorMessage(r));
	delete &httpTransaction;
	SendUserEvent(1, null);
}

void
ShotHttpSender::OnTransactionCertVerificationRequiredN (HttpSession &httpSession, HttpTransaction &httpTransaction, Osp::Base::String *pCert){
	AppLogDebug("OnTransactionCertVerificationRequiredN");
}

void
ShotHttpSender::OnTransactionCompleted (HttpSession &httpSession, HttpTransaction &httpTransaction) {
	AppLogDebug("OnTransactionCompleted");
	delete &httpTransaction;
	SendUserEvent(1, null);
}

void
ShotHttpSender::OnTransactionHeaderCompleted (HttpSession &httpSession, HttpTransaction &httpTransaction, int headerLen, bool bAuthRequired) {
	AppLogDebug("OnTransactionHeaderCompleted");
}

void
ShotHttpSender::OnTransactionReadyToRead (HttpSession &httpSession, HttpTransaction &httpTransaction, int availableBodyLen) {
	AppLogDebug("OnTransactionReadyToRead");
	if (availableBodyLen==0) {
		return;
	}
	HttpResponse* pResponse = httpTransaction.GetResponse();
	ByteBuffer* pBody = new ByteBuffer();
	pBody->Construct(availableBodyLen);
	pBody->Flip();
	pBody = pResponse->ReadBodyN();
	byte b;
	pBody->GetByte(b);
	AppLog("Response text is %d", b);
	if (shooter->getState()!=(int)b) {
		AppLog("Changing state from %d to %d", shooter->getState(), (int)b);
		shooter->setState((int)b);
	}
	//delete pBody;
}

void
ShotHttpSender::OnTransactionReadyToWrite (HttpSession &httpSession, HttpTransaction &httpTransaction, int recommendedChunkSize) {

	AppLogDebug("OnTransactionReadyToWrite");
	HttpTransaction* pTransaction = &httpTransaction;
	HttpRequest* pRequest = pTransaction->GetRequest();
	result r = E_SUCCESS;

	ByteBuffer* data = shot->GetBytes();

	if(data->GetRemaining()==0)
	{
		//Set a last chunked flag.
		AppLog("Sending the last chunk");
		ByteBuffer* body = new ByteBuffer();
		body->Construct(0);
		body->Flip();
		r =pRequest->WriteBody(*body);
		delete body;
		delete shot;
	} else {
		ByteBuffer* portion = new ByteBuffer();
		//Set a chunked data.
		int size = Math::Min(recommendedChunkSize, data->GetRemaining());
		portion -> Construct(size);
		AppLog("Sending %d bytes (recommended %d)", size, recommendedChunkSize);

		while(portion->GetPosition()<size) {
			byte b;
			data->GetByte(b);
			portion->SetByte(b);
		}
		portion->Flip();
		pRequest->WriteBody(*portion);
		portion->~ByteBuffer();
		delete portion;
	}

}

result
ShotHttpSender::Construct(void) {
	result r = E_SUCCESS;
	r = Thread::Construct(THREAD_TYPE_EVENT_DRIVEN);
	AppLogDebug("ShotHttpSender start result %s", GetErrorMessage(r));
	return r;
}

bool
ShotHttpSender::OnStart(void) {
	AppLogDebug("ShotHttpSender OnStarts");
	return true;
}

void
ShotHttpSender::OnStop(void) {
	AppLogDebug("ShotHttpSender OnStop");
}

void
ShotHttpSender::OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList *pArgs) {

		AppLogDebug("OnUserEventReceivedN");

		result r = E_SUCCESS;

		Thread::GetCurrentThread()->Sleep(500);

		shot = store->GetLastShotN();

		if (shot == null) {
			SendUserEvent(1, null);
			return;
		}

		AppLogDebug("Sending %S", shot->GetName()->GetPointer());

		String* uri = new String(*hostAddr);
		uri->Append("/beholder-master/post");
		AppLogDebug("URL is %S", uri->GetPointer());
		HttpHeader* pHeader= null;
		HttpTransaction* pHttpTransaction = null;

		// Get curent or make a new Http HttpSession
		if (session == null) {
			String* pProxyAddr = null;
			session = new HttpSession();
			session->Construct(NET_HTTP_SESSION_MODE_NORMAL, pProxyAddr, *hostAddr, null);
		}

		//Get new Transaction within the HttpSession
		pHttpTransaction = session->OpenTransactionN();
		AppLogDebug("Getting transacton %S", GetErrorMessage(GetLastResult()));
		if (GetLastResult()!=E_SUCCESS) {
			session = new HttpSession();
			session->Construct(NET_HTTP_SESSION_MODE_NORMAL, null, *hostAddr, null);
			SendUserEvent(1, null);
			AppLog("RETRYING Session");
		}

		// Add Listener
		pHttpTransaction->AddHttpTransactionListener(*this);

		// Get Http Request
		HttpRequest* pHttpRequest = pHttpTransaction->GetRequest();
		pHttpRequest->SetMethod(NET_HTTP_METHOD_POST);
		pHttpRequest->SetUri(*uri);

		pHeader = pHttpRequest->GetHeader();
		pHeader->AddField(L"Transfer-Encoding", L"chunked");

		//Enable OnTransactionReadyToWrite()
		r = pHttpTransaction->EnableTransactionReadyToWrite();
		AppLogDebug("Enable write: %S", GetErrorMessage(r));

		//Set a Body to Request.
		ByteBuffer* data = shot->GetBytes();
		ByteBuffer* portion = new ByteBuffer();
		portion -> Construct(1);
		byte b;
		data->GetByte(b);
		portion->SetByte(b);
		portion->Flip();

		r = pHttpRequest->WriteBody(*portion);
		AppLogDebug("Write result: %S", GetErrorMessage(r));

		// Submit a request with chunked mode
		r = pHttpTransaction->Submit();
		AppLogDebug("Submit result: %S", GetErrorMessage(r));

		delete portion;
		delete uri;

}
